package no.uials.distsys;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Anders
 */
public class Warehouse implements java.io.Serializable {

    public static final Logger LOG = Logger.getLogger(Warehouse.class.getName());
    private int lastArticleNumber;
    private int lastOrderNumber;
    private Map<String, User> users;
    private Map<String, Article> articles;
    private Map<Integer, Order> orders;
    


    public Warehouse() {
        lastArticleNumber = 0;
        lastOrderNumber = 0;
        users = new HashMap<>();
        articles = new HashMap<>();
        orders = new HashMap<>();
    }
    
    /**
     * Adds a user to the system, if the user
     * is already registered DistSysException is thrown
     * 
     * @param user
     * @return
     * @throws DistSysException 
     */
    public User addUser(User user) throws DistSysException {
        String uid = user.getName();
        if (users.containsKey(uid)) {
            throw new DistSysException("User " + uid + " does already exist. Try another name.");
        }
        users.put(uid, user);
        return users.get(uid);
    }
    
    /**
     * Adds a user with password and role
     * 
     * @param uid
     * @param pwd
     * @param role
     * @return 
     */
    public User addUser(String uid, String pwd, User.Role... role) {
        User user = new User(pwd, pwd, role);
        return user;
    }
    
    /**
     * Used to change the password of a specific user
     * 
     * 
     * @param user
     * @param oldPwd
     * @param newPwd
     * @return
     * @throws DistSysException 
     */
    public boolean changePassword(User user, String oldPwd, String newPwd) throws DistSysException {
        return user.changePwd(oldPwd, newPwd);
    }
    
    
    /**
     * Returns a list of users registered
     * 
     * @return 
     */
    public Map<String, User> getUsers() {
        return users;
    }
    
    
    /**
     * 
     * Searching for a specific user,
     * throws DistSysException if user is not registered
     * 
     * @param uid
     * @return
     * @throws DistSysException 
     */
    public User getUser(String uid) throws DistSysException {
        if (!users.containsKey(uid)) {
            throw new DistSysException("Ugyldig brukernavn.");
        }
        return users.get(uid);
    }
    
    
    /**
     * 
     * Adds an article to the warehouse
     * 
     * @param name
     * @param price
     * @param stock
     * @param aisle
     * @param section
     * @param shelf
     * @return 
     */
    public Article addArticle(String name, Double price, int stock, int aisle, int section, int shelf){
        return addArticle(name, price, stock, new Position(aisle, section, shelf));
    }
    
    
    /**
     * 
     * 
     * 
     * @param name
     * @param price
     * @param stock
     * @param position
     * @return 
     */
    public Article addArticle(String name, Double price, int stock, Position position) {
        lastArticleNumber++;
        String id = "ID" + addZero(lastArticleNumber, 3);
        if (articles.containsKey(id)) {
            articles.get(id).changeStock(stock);
        } else {
            articles.put(id, new Article(id, name, price, stock, position));
        }
        return articles.get(id);
    }
    
    
    /**
     * 
     * Updates the list of articles available
     * 
     * @param article
     * @param number
     * @return 
     */
    public int updateStock(Article article, int number) {
        String id = article.getID();
        if (!articles.containsKey(id)) {
            LOG.log(Level.INFO, "The article does not preexist in the system, adding article to the system.");
            addArticle(article.getName(), article.getPrice(), article.getStock(), article.getPosition());
            if (article.getStock() != number) {
                article.setStock(number);
            }
            return number;
        } else {
            return article.changeStock(number);
        }
    }
    
    
    /**
     * Returns list of all articles
     * 
     * @return 
     */
    public Map<String, Article> getArticles() {
        return articles;
    }
    
    
    /**
     * 
     * Used to remove an article based on article ID,
     * throws DistSysException if the ID is not found
     * 
     * @param id
     * @return
     * @throws DistSysException 
     */
    public Article removeArticle(String id) throws DistSysException {
        if (!articles.containsKey(id)) {
            throw new DistSysException("No articles with ID " + id + " exists in the system.");
        }
        return articles.remove(id);
    }
    
    
    /**
     * 
     * Removes an article from the system
     * 
     * @param article
     * @return
     * @throws DistSysException 
     */
    public Article removeArticle(Article article) throws DistSysException {
        return removeArticle(article.getID());
    }
    
    
    /**
     * 
     * Place Order
     * 
     * @param user
     * @param orderLines
     * @return
     * @throws DistSysException 
     */
    public int placeOrder(User user, Map<String, OrderLine> orderLines) throws DistSysException {
        Iterator itr = orderLines.keySet().iterator();
        String id = null;
        while (itr.hasNext()) {
            id = (String) itr.next();
            Article curr = articles.get(id);
            if (curr.getStock() == 0) {
                throw new DistSysException(curr.getName() + " is out of stock.");
            } else if (orderLines.get(id).getUnits() > curr.getStock()) {
                throw new DistSysException("Not enough units of " + curr.getName() + " left");
            }
        }
        itr = orderLines.keySet().iterator();
        while (itr.hasNext()) {
            id = (String) itr.next();
            articles.get(id).changeStock(-orderLines.get(id).getUnits());
        }
        lastOrderNumber++;
        Order order = new Order(lastOrderNumber, user, orderLines);
        orders.put(lastOrderNumber, order);
        return lastOrderNumber;
    }
    
    
    /**
     * Returns list of all orders
     * 
     * @return 
     */
    public Map<Integer, Order> getAllOrders() {
        return orders;
    }
    
    
    /**
     * 
     * Returns Orders connected to a specific user
     * 
     * @param user
     * @return 
     */
    public Map<Integer, Order> getUserOrders(String user) {
        Iterator itr = orders.keySet().iterator();
        Map<Integer, Order> retVal = new HashMap<>();
        Integer id = null;
        while (itr.hasNext()) {
            id = (Integer) itr.next();
            Order check = orders.get(id);
            if (check.getUser().getName().equals(user)) {
                retVal.put(id, check);
            }
        }
        return retVal;
    }
    
    
    /**
     * 
     * Print Order
     * 
     * @param orderNumber
     * @return
     * @throws DistSysException 
     */
    public String printOrder(int orderNumber) throws DistSysException {
        String retVal = null;
        if (!orders.containsKey(orderNumber)) {
            throw new DistSysException("The order does not exist.");
        }
        Order order = orders.get(orderNumber);
//        TODO: Lage oppsett på ordreutskrift.
        return retVal;
    }
    
    
    /**
     * 
     * @param num
     * @param length
     * @return 
     */
    private String addZero(int num, int length) {
        String retVal = num + "";
        while (retVal.length() < length) {
            retVal = 0 + retVal;
        }
        return retVal;
    }
}